﻿using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using FileTreeSpace;
using TravViewed;
using WinController;

namespace WinView
{
    public class DetailView : IDetailView
    {
        private TravModelbase appModelbase;
        private DetailModelbase detailModelbase;
        private ListView widget;
        private AppController appController;

        #region CONSTRUCTORS

        public DetailView (AppController controller, TravModelbase appModelbase, DetailModelbase detailModelbase)
        {
            this.appController = controller;
            widget = controller.details;

            detailModelbase.View = this;
            this.detailModelbase = detailModelbase;
            this.appModelbase = appModelbase;

            this.appModelbase.FolderRenamed += RenameFolder;
            this.appModelbase.FolderRemoved += RemoveFolder;
            this.appModelbase.AddressChanged += Load;

            this.detailModelbase.FileAdded += AddFile;
            this.detailModelbase.FileChanged += ChangeFile;
            this.detailModelbase.FileRenamed += RenameFile;
            this.detailModelbase.FileRemoved += RemoveFile;
        }

        #endregion

        #region PRESENTERS

        public void SelectNone ()
        {
            appController.SupressStatusUpdates = true;
            for (int i = 0; i < widget.Items.Count; ++i)
                widget.Items[i].Selected = false;
            appController.SupressStatusUpdates = false;
        }


        public IEnumerable SelectedFullNames
        {
            get
            {
                for (int i = 0; i < SelectedCount; ++i)
                    yield return FullName (SelectionIndex (i));
            }
        }

        public IEnumerable FullNames
        {
            get
            {
                for (int i = 0; i < Count; ++i)
                    yield return FullName (i);
            }
        }


        public void Select ()
        { widget.Select (); }

        public int Count { get { return widget.Items.Count; } }
        public int SelectedCount { get { return widget.SelectedItems.Count; } }
        public bool IsSelected (int index) { return widget.Items[index].Selected; }
        public void SetIsSelected (int index, bool isSelected) { widget.Items[index].Selected = isSelected; }
        public int SelectionIndex (int index) { return widget.SelectedIndices[index]; }

        #endregion

        #region INTERFACED OBSERVERS

        public void AddFile (string newBaseName, long newSize, string newHash, string newPathName, DateTime newModifyDate, FileAttributes attribs)
        {
            int rootLen = detailModelbase.TravView.RootDir.Length;
            string relPath = rootLen >= newPathName.Length ? "" : newPathName.Substring (rootLen + 1);

            string cd = appModelbase.CurrentDir;

            if (! appModelbase.DetailView.IsSubfoldersShown)
                if (cd.Length < newPathName.Length)
                    return;

            ListViewItem item = new ListViewItem (newBaseName);
            item.Font = appController.DetailFont;
            item.SubItems.Add (newSize.ToString ());
            item.SubItems.Add (relPath);
            item.SubItems.Add (newHash);
            item.SubItems.Add (newPathName);
            item.SubItems.Add (newModifyDate.ToString ("u"));
            setAttributes (item, attribs);

            widget.Items.Add (item);
        }


        public void ChangeFile (string fullName, long newSize, FileAttributes newAttributes)
        {
            for (int i = 0; i < widget.Items.Count; i++)
                if (FullName (i) == fullName)
                {
                    SetHash (i, "");
                    SetFileSize (i, newSize);
                    SetAttributes (i, newAttributes);
                    return;
                }
        }


        public void RenameFile (string oldFullName, string newFullName, string newBaseName)
        {
            for (int i = 0; i < widget.Items.Count; ++i)
                if (FullName (i) == oldFullName)
                {
                    SetBaseName (i, newBaseName);
                    return;
                }
                else if (FullName (i) == newFullName)
                    return;

            //Debug.Fail ("FileRenamer missing row");
        }


        public void RemoveFile (string fullName)
        {
            for (int i = 0; i < widget.Items.Count; ++i)
                if (FullName (i) == fullName)
                {
                    widget.Items.RemoveAt (i);
                    return;
                }

            //Debug.Fail ("FileDeleter missing row");
        }


        public string BaseName (int index)
        { return widget.Items[index].SubItems[AppController.ColumnBaseName].Text; }

        public void SetBaseName (int index, string newValue)
        { widget.Items[index].SubItems[AppController.ColumnBaseName].Text = newValue; }

        public string FullName (int index)
        { return widget.Items[index].SubItems[AppController.ColumnFullPathName].Text + "\\" + widget.Items[index].SubItems[AppController.ColumnBaseName].Text; }

        public string FullPathName (int index)
        { return widget.Items[index].SubItems[AppController.ColumnFullPathName].Text; }

        public void SetFullPathName (int index, string newValue)
        {
            widget.Items[index].SubItems[AppController.ColumnFullPathName].Text = newValue;

            int rootLen = detailModelbase.TravView.RootDir.Length;
            string relPath = rootLen >= newValue.Length ? "" : newValue.Substring (rootLen + 1);
            widget.Items[index].SubItems[AppController.ColumnRelativePathName].Text = relPath;
        }

        public string GetExtension (int index)
        { return Path.GetExtension (widget.Items[index].SubItems[AppController.ColumnBaseName].Text); }

        public long FileSize (int index)
        {
            string sizeStr = widget.Items[index].SubItems[AppController.ColumnSize].Text;
            long size = 0;
            long.TryParse (sizeStr, out size);
            return size;
        }

        public void SetFileSize (int index, long newValue)
        { widget.Items[index].SubItems[AppController.ColumnSize].Text = newValue.ToString (); }

        public string Hash (int index)
        { return widget.Items[index].SubItems[AppController.ColumnHash].Text; }

        public void SetHash (int index, string newHash)
        { widget.Items[index].SubItems[AppController.ColumnHash].Text = newHash; }

        public DateTime ModifyDate (int index)
        {
            string s = widget.Items[index].SubItems[AppController.ColumnModifyDate].Text;
            DateTime result;
            DateTime.TryParse (s, CultureInfo.CurrentUICulture, DateTimeStyles.None, out result);
            return result;
        }

        public void SetModifyDate (int index, DateTime newValue)
        { widget.Items[index].SubItems[AppController.ColumnModifyDate].Text = newValue.ToString (); }

        private void setAttributes (ListViewItem item, FileAttributes newAttributes)
        {
            if ((newAttributes & (FileAttributes.Hidden | FileAttributes.ReadOnly)) == (FileAttributes.Hidden | FileAttributes.ReadOnly))
                item.ForeColor = Color.Orange;
            else if ((newAttributes & FileAttributes.Hidden) == FileAttributes.Hidden)
                item.ForeColor = Color.Green;
            else if ((newAttributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
                item.ForeColor = Color.Red;
            else if ((newAttributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
                item.ForeColor = Color.BlueViolet;
            else
                item.ForeColor = widget.ForeColor;
        }

        public void SetAttributes (int index, FileAttributes newAttributes)
        { setAttributes (widget.Items[index], newAttributes); }

        #endregion

        #region OBSERVERS

        public void Load ()
        {
            widget.Items.Clear ();

            var path = detailModelbase.TravView.CurrentDirPath;
            if (path == null || path.Count == 0)
                return;

            widget.BeginUpdate ();

            if (!detailModelbase.IsSubfoldersShown)
                showDir (path.Leaf, path.PathName);
            else
                foreach (DirPath subPath in path)
                    showDir (subPath.Leaf, subPath.PathName);

            widget.EndUpdate ();
        }


        public void RenameFolder (string oldPathName, string oldLeafName, string newLeafName)
        {
            int oldLen = oldPathName.Length;
            for (int i = 0; i < Count; i++)
            {
                string itemPath = FullPathName (i);

                if (itemPath.Length == oldLen || itemPath.Length > oldLen && itemPath[oldLen] == '\\')
                    if (itemPath.StartsWith (oldPathName, true, null))
                    {
                        string oldParentName = oldPathName.Substring (0, oldLen - oldLeafName.Length);
                        SetFullPathName (i, oldParentName + newLeafName + itemPath.Substring (oldLen));
                    }
            }
        }


        public void RemoveFolder (string oldPathName)
        {
            int len = oldPathName.Length;
            for (int i = Count - 1; i >= 0; i--)
            {
                string itemPath = FullPathName (i);
                if (itemPath.Length == len || itemPath.Length > len && itemPath[len] == '\\')
                    if (itemPath.Substring (0, len) == oldPathName)
                        widget.Items.RemoveAt (i);
            }
        }

        #endregion

        #region OBSERVER HELPERS

        private long showDir (DirItem dir, string pathName)
        {
            long result = 0;

            foreach (FileItem file in dir.Files)
            {
                string hash = "";
                if (file.Hash != null)
                    hash = file.Hash.ToString ();

                AddFile (file.Name, file.Size, hash, pathName, file.DateModified, file.Attributes);

                result += file.Size;
            }

            return result;
        }


        #endregion
    }
}
